use crate::{
	JArray, JArrayObject, JArrayPrim, JArrayPrimMaker, JBool, JByte, JChar, JClassID, JDouble, JFloat, JInt, JLong, JObject, JPlainMarker,
	JShort,
};

///
///
///
///
pub type JValue = sys::jvalue;

///
///
///
///
pub trait AsJValue {
	fn as_jvalue(&self) -> JValue;
}
impl AsJValue for () {
	fn as_jvalue(&self) -> JValue {
		JValue { j: 0 }
	}
}
impl AsJValue for JBool {
	fn as_jvalue(&self) -> JValue {
		JValue { z: *self }
	}
}
impl AsJValue for JByte {
	fn as_jvalue(&self) -> JValue {
		JValue { b: *self }
	}
}
impl AsJValue for JChar {
	fn as_jvalue(&self) -> JValue {
		JValue { c: *self }
	}
}
impl AsJValue for JShort {
	fn as_jvalue(&self) -> JValue {
		JValue { s: *self }
	}
}
impl AsJValue for JInt {
	fn as_jvalue(&self) -> JValue {
		JValue { i: *self }
	}
}
impl AsJValue for JLong {
	fn as_jvalue(&self) -> JValue {
		JValue { j: *self }
	}
}
impl AsJValue for JFloat {
	fn as_jvalue(&self) -> JValue {
		JValue { f: *self }
	}
}
impl AsJValue for JDouble {
	fn as_jvalue(&self) -> JValue {
		JValue { d: *self }
	}
}
impl AsJValue for sys::jobject {
	fn as_jvalue(&self) -> JValue {
		JValue { l: self.clone() }
	}
}
impl<T: AsRef<JObject>> AsJValue for Option<&T> {
	fn as_jvalue(&self) -> JValue {
		match self {
			Some(v) => JValue { l: v.as_ref().as_sys() },
			None => JValue { l: core::ptr::null_mut() },
		}
	}
}
impl<T: AsRef<JObject>> AsJValue for &T {
	fn as_jvalue(&self) -> JValue {
		self.as_ref().as_sys().as_jvalue()
	}
}

///
///
///
///
pub trait FromJValue: Sized {
	unsafe fn from_jvalue(value: JValue) -> Option<Self>;
}
impl FromJValue for () {
	unsafe fn from_jvalue(_: JValue) -> Option<Self> {
		Some(())
	}
}
impl FromJValue for JBool {
	unsafe fn from_jvalue(value: JValue) -> Option<Self> {
		Some(value.z)
	}
}
impl FromJValue for JByte {
	unsafe fn from_jvalue(value: JValue) -> Option<Self> {
		Some(value.b)
	}
}
impl FromJValue for JChar {
	unsafe fn from_jvalue(value: JValue) -> Option<Self> {
		Some(value.c)
	}
}
impl FromJValue for JShort {
	unsafe fn from_jvalue(value: JValue) -> Option<Self> {
		Some(value.s)
	}
}
impl FromJValue for JInt {
	unsafe fn from_jvalue(value: JValue) -> Option<Self> {
		Some(value.i)
	}
}
impl FromJValue for JLong {
	unsafe fn from_jvalue(value: JValue) -> Option<Self> {
		Some(value.j)
	}
}
impl FromJValue for JFloat {
	unsafe fn from_jvalue(value: JValue) -> Option<Self> {
		Some(value.f)
	}
}
impl FromJValue for JDouble {
	unsafe fn from_jvalue(value: JValue) -> Option<Self> {
		Some(value.d)
	}
}
impl FromJValue for sys::jobject {
	unsafe fn from_jvalue(value: JValue) -> Option<Self> {
		if value.l.is_null() {
			return None;
		}
		Some(value.l)
	}
}
impl<T: AsRef<JObject> + JPlainMarker> FromJValue for &T {
	unsafe fn from_jvalue(value: JValue) -> Option<Self> {
		if value.l.is_null() {
			return None;
		}
		unsafe { (&*(value.l as *mut JObject)).cast_unchecked() }
	}
}
impl FromJValue for &JArray {
	unsafe fn from_jvalue(value: JValue) -> Option<Self> {
		if value.l.is_null() {
			return None;
		}
		Some(unsafe { &*(value.l as *mut JArray) })
	}
}
impl<T: AsRef<JObject>> FromJValue for &JArrayObject<T> {
	unsafe fn from_jvalue(value: JValue) -> Option<Self> {
		if value.l.is_null() {
			return None;
		}
		Some(unsafe { &*(value.l as *mut JArrayObject<T>) })
	}
}
impl<T: JArrayPrimMaker> FromJValue for &JArrayPrim<T> {
	unsafe fn from_jvalue(value: JValue) -> Option<Self> {
		if value.l.is_null() {
			return None;
		}
		Some(unsafe { &*(value.l as *mut JArrayPrim<T>) })
	}
}
impl FromJValue for JClassID {
	unsafe fn from_jvalue(value: JValue) -> Option<Self> {
		if value.l.is_null() {
			return None;
		}
		unsafe { JClassID::from_sys(value.l) }
	}
}

///
///
///
///
///
pub trait AsJValueArray<const N: usize> {
	fn as_jvalue_array(&self) -> [JValue; N];
}

impl AsJValueArray<0> for () {
	fn as_jvalue_array(&self) -> [JValue; 0] {
		[]
	}
}

macro_rules! tuple_impl_serial {
	($len:tt $($n:tt $name:ident)*) => {
		impl<$($name:AsJValue,)*> AsJValueArray<$len> for ($($name,)*) {
			fn as_jvalue_array(&self) -> [JValue; $len] {
				[$(self.$n.as_jvalue(),)*]
			}
		}
	};
}

tuple_impl_serial!(1 0 A);
tuple_impl_serial!(2 0 A 1 B);
tuple_impl_serial!(3 0 A 1 B 2 C);
tuple_impl_serial!(4 0 A 1 B 2 C 3 D);
tuple_impl_serial!(5 0 A 1 B 2 C 3 D 4 E);
tuple_impl_serial!(6 0 A 1 B 2 C 3 D 4 E 5 F);
tuple_impl_serial!(7 0 A 1 B 2 C 3 D 4 E 5 F 6 G);
tuple_impl_serial!(8 0 A 1 B 2 C 3 D 4 E 5 F 6 G 7 H);
tuple_impl_serial!(9 0 A 1 B 2 C 3 D 4 E 5 F 6 G 7 H 8 I);
tuple_impl_serial!(10 0 A 1 B 2 C 3 D 4 E 5 F 6 G 7 H 8 I 9 J);
tuple_impl_serial!(11 0 A 1 B 2 C 3 D 4 E 5 F 6 G 7 H 8 I 9 J 10 K);
tuple_impl_serial!(12 0 A 1 B 2 C 3 D 4 E 5 F 6 G 7 H 8 I 9 J 10 K 11 L);
tuple_impl_serial!(13 0 A 1 B 2 C 3 D 4 E 5 F 6 G 7 H 8 I 9 J 10 K 11 L 12 M);
tuple_impl_serial!(14 0 A 1 B 2 C 3 D 4 E 5 F 6 G 7 H 8 I 9 J 10 K 11 L 12 M 13 N);
tuple_impl_serial!(15 0 A 1 B 2 C 3 D 4 E 5 F 6 G 7 H 8 I 9 J 10 K 11 L 12 M 13 N 14 O);
tuple_impl_serial!(16 0 A 1 B 2 C 3 D 4 E 5 F 6 G 7 H 8 I 9 J 10 K 11 L 12 M 13 N 14 O 15 P);
tuple_impl_serial!(17 0 A 1 B 2 C 3 D 4 E 5 F 6 G 7 H 8 I 9 J 10 K 11 L 12 M 13 N 14 O 15 P 16 Q);
tuple_impl_serial!(18 0 A 1 B 2 C 3 D 4 E 5 F 6 G 7 H 8 I 9 J 10 K 11 L 12 M 13 N 14 O 15 P 16 Q 17 R);
tuple_impl_serial!(19 0 A 1 B 2 C 3 D 4 E 5 F 6 G 7 H 8 I 9 J 10 K 11 L 12 M 13 N 14 O 15 P 16 Q 17 R 18 S);
tuple_impl_serial!(20 0 A 1 B 2 C 3 D 4 E 5 F 6 G 7 H 8 I 9 J 10 K 11 L 12 M 13 N 14 O 15 P 16 Q 17 R 18 S 19 T);
